package com.leantech.android.browser.ui.browser

import android.app.Activity
import android.app.Dialog
import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.net.Uri
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.webkit.PermissionRequest
import android.webkit.ValueCallback
import android.webkit.WebBackForwardList
import android.webkit.WebChromeClient
import androidx.activity.result.contract.ActivityResultContracts
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams
import androidx.fragment.app.Fragment
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.recyclerview.widget.RecyclerView.AdapterDataObserver
import com.cscj.android.repository.db.entity.HotSearchEntity
import com.cscj.android.repository.db.entity.ShortCutEntryEntity
import com.cscj.android.repository.network.Result
import com.cscj.android.utils.BitmapUtils
import com.cscj.android.utils.LOG
import com.google.android.material.appbar.AppBarLayout.ScrollingViewBehavior
import com.google.android.material.snackbar.Snackbar
import com.lean.android.ad.core.AdLoaders
import com.lean.android.ad.utils.NetworkUtils
import com.leantech.android.browser.R
import com.leantech.android.browser.browser.BrowserDelegate
import com.leantech.android.browser.browser.BrowserTab
import com.leantech.android.browser.browser.WebViewCallback
import com.leantech.android.browser.browser.WebViewController
import com.leantech.android.browser.browser.web.FullScreenSupport
import com.leantech.android.browser.browser.web.RocketWebView
import com.leantech.android.browser.browser.web.RocketWebViewClient
import com.leantech.android.browser.databinding.FragmentBrowserBinding
import com.leantech.android.browser.dialog.ConfirmWithCheckboxDialog
import com.leantech.android.browser.ui.CodeScanActivity
import com.leantech.android.browser.ui.InterstitialAdViewModel
import com.leantech.android.browser.ui.browser.adapter.HotSearchMarqueeAdapter
import com.leantech.android.browser.ui.browser.adapter.ShortCutEntryAdapter
import com.leantech.android.browser.ui.browser.viewmodel.BrowserViewModel
import com.leantech.android.browser.ui.browser.viewmodel.FavoriteStateViewModel
import com.leantech.android.browser.ui.browser.viewmodel.ShortCutEntryViewModel
import com.leantech.android.browser.ui.favorites.FavoritesActivity
import com.leantech.android.browser.ui.shortcut.ShortCutActivity
import com.leantech.android.browser.utils.PermissionExplainDialog
import com.leantech.android.browser.utils.awaitSplashAd
import com.leantech.android.browser.utils.failToast
import com.leantech.android.browser.utils.gone
import com.leantech.android.browser.utils.invisible
import com.leantech.android.browser.utils.isGone
import com.leantech.android.browser.utils.onThrottleClick
import com.leantech.android.browser.utils.show
import com.leantech.android.browser.utils.toast
import com.leantech.android.browser.utils.visible
import com.permissionx.guolindev.PermissionX
import com.qmuiteam.qmui.kotlin.dip
import com.qmuiteam.qmui.skin.QMUISkinManager
import com.shencoder.pagergridlayoutmanager.PagerGridLayoutManager
import com.tbuonomo.viewpagerdotsindicator.BaseDotsIndicator
import com.tbuonomo.viewpagerdotsindicator.OnPageChangeListenerHelper
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import org.koin.android.ext.android.getKoin
import org.koin.androidx.viewmodel.ext.android.activityViewModel
import org.koin.androidx.viewmodel.ext.android.viewModel
import splitties.fragmentargs.arg
import splitties.fragments.start
import splitties.resources.color
import kotlin.math.min

/**
 * 每新建一个浏览器Tab，则新增一个BrowserFragment实例
 * 每个BrowserFragment对应一个RocketWebView
 * 使用Fragment来管理webView是因为需要考虑到生命周期，WebView作为组件，不适合直接与生命周期绑定
 */
class BrowserFragment : Fragment(), WebViewCallback, BrowserTab,
    HotSearchMarqueeAdapter.HotSearchMarqueeCallback,
    ShortCutEntryAdapter.ShortCutEntryAdapterCallback {

    private lateinit var binding: FragmentBrowserBinding

    private var mUrl: String by arg()

    private lateinit var webView: RocketWebView

    private lateinit var browserDelegate: BrowserDelegate
    private val browserViewModel by activityViewModel<BrowserViewModel>()
    private val adViewModel by activityViewModel<InterstitialAdViewModel>()
    private val favoriteStateViewModel by viewModel<FavoriteStateViewModel>()
    private val shortCutEntryViewModel by activityViewModel<ShortCutEntryViewModel>()

    private val hotSearchUrl = getKoin().getProperty("hotSearchUrl", "")
    private val appClient = getKoin().getProperty("appClient", "")

    private var title: String? = "首页"
    private var faviconBitmap: Bitmap? = null
    private var previewBitmap: Bitmap? = null
    private var previewDirty: Boolean = false

    private lateinit var baiduMarqueeAdapter: HotSearchMarqueeAdapter
    private lateinit var toutiaoMarqueeAdapter: HotSearchMarqueeAdapter
    private lateinit var weiboMarqueeAdapter: HotSearchMarqueeAdapter

    private lateinit var pagerGridLayoutManager: PagerGridLayoutManager

    private lateinit var shortCutEntryAdapter: ShortCutEntryAdapter
    private val autoHeightObserver = object : AdapterDataObserver() {
        override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
            super.onItemRangeInserted(positionStart, itemCount)
            updateRecyclerViewHeight()
        }

        override fun onItemRangeRemoved(positionStart: Int, itemCount: Int) {
            super.onItemRangeRemoved(positionStart, itemCount)
            updateRecyclerViewHeight()
        }
    }

    private val onSkinChangeListener = QMUISkinManager.OnSkinChangeListener { _, _, _ ->
        shortCutEntryAdapter.updateButtonSkin()
        previewDirty = true
    }

    private lateinit var editSnackbar: Snackbar

    private val scanCodeForResult =
        registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
            if (result.resultCode == Activity.RESULT_OK) {
                val text = result.data?.getStringExtra(CodeScanActivity.ResultExtraText)
                if (!text.isNullOrBlank()) {
                    loadUrlOrSearch(text)
                }
            }
        }

    private lateinit var permissionExplainPopup: Dialog

    private lateinit var blockIntentDialog: ConfirmWithCheckboxDialog

    companion object {
        private const val LOG_TAG = "RocketBrowser"
        fun createInstance(url: String = ""): BrowserFragment {
            return BrowserFragment().apply {
                mUrl = url
            }
        }
    }

    private val _backStackFlow = MutableStateFlow<List<BrowserTab.BackStackItem>>(emptyList())

    private val _backStateFlow = MutableStateFlow(false)

    private val _forwardStateFlow = MutableStateFlow(false)

    private val _currentUrlFlow = MutableStateFlow("" to "")

    private val fullScreenSupport by lazy {
        FullScreenSupport(requireActivity())
    }

    override val backStackFlow: Flow<List<BrowserTab.BackStackItem>>
        get() = _backStackFlow

    override val backStateFlow: Flow<Boolean>
        get() = _backStateFlow
    override val forwardStateFlow: Flow<Boolean>
        get() = _forwardStateFlow

    override val favoriteStateFlow: Flow<Boolean>
        get() = favoriteStateViewModel.favoriteState

    override val currentUrlFlow: Flow<Pair<String, String>>
        get() = _currentUrlFlow

    override fun onAttach(context: Context) {
        super.onAttach(context)
        if (context is BrowserDelegate) {
            browserDelegate = context
        } else {
            throw IllegalStateException("activity must implement BrowserDelegate")
        }
    }

    private fun getRankUrl(sourceType: Int): String {
        val uriBuilder = Uri.parse(hotSearchUrl).buildUpon()
        uriBuilder.appendQueryParameter("id", "$sourceType")
            .appendQueryParameter("appClient", appClient)
        return uriBuilder.toString()
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
    ): View? {
        binding = FragmentBrowserBinding.inflate(inflater, container, false)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        initView()

        loadUrl(mUrl, false)
        subscribeFlow()

        loadFeedAd()
    }

    private fun subscribeFlow() {
        viewLifecycleOwner.lifecycleScope.launch {
            repeatOnLifecycle(Lifecycle.State.STARTED) {
                launch {
                    browserViewModel.currentUaFlow.collectLatest { ua ->
                        ua?.also {
                            LOG.d(LOG_TAG, "user agent change to ${it.name}")
                            if (::webView.isInitialized) {
                                webView.updateUserAgent(it.content)
                            }
                        }
                    }
                }

                launch {
                    browserViewModel.fontSizeFlow.collectLatest {
                        LOG.d(LOG_TAG, "font size change to $it")
                        if (::webView.isInitialized) {
                            webView.updateFontSize(it)
                        }
                    }
                }

                launch {
                    browserViewModel.imageModeFlow.collectLatest {
                        LOG.d(LOG_TAG, "image mode change to $it")
                        if (::webView.isInitialized) {
                            webView.updateImageMode(it)
                        }
                    }
                }

                launch {
                    browserViewModel.darkModeFlow.collectLatest {
                        LOG.d(LOG_TAG, "dark mode change to $it")
                        if (::webView.isInitialized) {
                            webView.updateDarkMode(it)
                        }
                    }
                }

                launch {
                    favoriteStateViewModel.favoriteState.collectLatest {
                        binding.btnCollect.isSelected = it
                        binding.btnCollect.visibility = View.VISIBLE
                    }
                }

                launch {
                    browserViewModel.baiduHotSearchFlow.collectLatest {
                        baiduMarqueeAdapter.setData(it)
                    }
                }

                launch {
                    browserViewModel.toutiaoHotSearchFlow.collectLatest {
                        toutiaoMarqueeAdapter.setData(it)
                    }
                }

                launch {
                    browserViewModel.weiboHotSearchFlow.collectLatest {
                        weiboMarqueeAdapter.setData(it)
                    }
                }

                launch {
                    shortCutEntryViewModel.localShortCutEntryFlow.collectLatest {
                        shortCutEntryAdapter.submitList(it)
                        if (it.isEmpty() && ::editSnackbar.isInitialized) {
                            shortCutEntryAdapter.updateEditMode(false)
                            editSnackbar.dismiss()
                        }

                        binding.recyclerView.postDelayed({
                            val pagerCount = pagerGridLayoutManager.pagerCount
                            binding.dotIndicator.show(pagerCount > 1)
                            binding.dotIndicator.refreshDots()
                        }, 500)

                    }
                }

                launch {
                    browserViewModel.webConfigFlow.collectLatest {
                        if (::webView.isInitialized) {
                            LOG.d("BrowserFragment", "webConfig update $it")
                            webView.config = it
                        }
                    }
                }
            }
        }
    }

    private fun updateRecyclerViewHeight() {
        val itemCount = shortCutEntryAdapter.dataCount
        val rows = min(
            itemCount / ShortCutEntryAdapter.maxColumnCount + 1, ShortCutEntryAdapter.maxRowCount
        ) //至少一行
        val rowHeight = dip(84)
        binding.recyclerView.updateLayoutParams {
            height = rowHeight * rows
        }

        if (::pagerGridLayoutManager.isInitialized) {
            pagerGridLayoutManager.rows = rows
        }

    }

    private fun initView() {
        binding.btnSearch.onThrottleClick {
            browserDelegate.showSearchFragment("", true)
        }

        binding.textSearch.onThrottleClick {
            browserDelegate.showSearchFragment("", false)
        }

        binding.btnAction.onThrottleClick {
            if (NetworkUtils.isNetworkConnected()) {
                reload()
            } else {
                failToast("网络不给力")
            }

        }

        binding.btnCollect.onThrottleClick {
            toggleFavorite()
        }

        baiduMarqueeAdapter = HotSearchMarqueeAdapter(this)
        toutiaoMarqueeAdapter = HotSearchMarqueeAdapter(this)
        weiboMarqueeAdapter = HotSearchMarqueeAdapter(this)

        binding.marqueeView1.setAdapter(baiduMarqueeAdapter)
        binding.marqueeView2.setAdapter(toutiaoMarqueeAdapter)
        binding.marqueeView3.setAdapter(weiboMarqueeAdapter)

        binding.textSource1.onThrottleClick {
            loadUrl(getRankUrl(HotSearchEntity.SourceTypeBaidu), true)
            adViewModel.requestLoadAd()
        }
        binding.btnMore1.onThrottleClick {
            loadUrl(getRankUrl(HotSearchEntity.SourceTypeBaidu), true)
            adViewModel.requestLoadAd()
        }

        binding.textSource2.onThrottleClick {
            loadUrl(getRankUrl(HotSearchEntity.SourceTypeTouTiao), true)
            adViewModel.requestLoadAd()
        }
        binding.btnMore2.onThrottleClick {
            loadUrl(getRankUrl(HotSearchEntity.SourceTypeTouTiao), true)
            adViewModel.requestLoadAd()
        }

        binding.textSource3.onThrottleClick {
            loadUrl(getRankUrl(HotSearchEntity.SourceTypeWeibo), true)
            adViewModel.requestLoadAd()
        }
        binding.btnMore3.onThrottleClick {
            loadUrl(getRankUrl(HotSearchEntity.SourceTypeWeibo), true)
            adViewModel.requestLoadAd()
        }

        binding.btnScan.onThrottleClick {
            permissionExplainPopup = PermissionExplainDialog.createDialog(
                requireContext(), "相机权限", "获取相机权限是为了实现扫一扫功能"
            )
            permissionExplainPopup.show()

            PermissionX.init(this).permissions(android.Manifest.permission.CAMERA)
                .onForwardToSettings { scope, deniedList ->
                    scope.showForwardToSettingsDialog(
                        deniedList,
                        "相机权限已被拒绝，如需使用扫一扫功能请去开启该权限",
                        "去开启",
                        "不开启"
                    )
                }.request { allGranted, _, _ ->
                    if (::permissionExplainPopup.isInitialized) {
                        permissionExplainPopup.dismiss()
                    }

                    if (allGranted) {
                        awaitSplashAd {
                            scanCodeForResult.launch(
                                Intent(
                                    requireContext(), CodeScanActivity::class.java
                                )
                            )
                        }
                    }
                }
        }

        initEntryRecyclerView()
    }

    private fun initEntryRecyclerView() {
        shortCutEntryAdapter = ShortCutEntryAdapter(this)
        shortCutEntryAdapter.registerAdapterDataObserver(autoHeightObserver)
        binding.recyclerView.adapter = shortCutEntryAdapter
        PagerGridLayoutManager.setDebug(true)
        pagerGridLayoutManager = PagerGridLayoutManager(
            ShortCutEntryAdapter.maxRowCount, ShortCutEntryAdapter.maxColumnCount
        ).apply {

            isHandlingSlidingConflictsEnabled = true
        }

        binding.dotIndicator.pager = object : BaseDotsIndicator.Pager {
            override val count: Int
                get() = pagerGridLayoutManager.pagerCount
            override val currentItem: Int
                get() = pagerGridLayoutManager.currentPagerIndex
            override val isEmpty: Boolean
                get() = pagerGridLayoutManager.itemCount == 0
            override val isNotEmpty: Boolean
                get() = pagerGridLayoutManager.itemCount > 0

            override fun addOnPageChangeListener(onPageChangeListenerHelper: OnPageChangeListenerHelper) {
                pagerGridLayoutManager.setPagerChangedListener(object :
                    PagerGridLayoutManager.PagerChangedListener {
                    override fun onPagerCountChanged(pagerCount: Int) {
                        binding.dotIndicator.show(pagerCount > 1)
                        binding.dotIndicator.refreshDots()
                    }

                    override fun onPagerIndexSelected(
                        prePagerIndex: Int, currentPagerIndex: Int
                    ) {
                        onPageChangeListenerHelper.onPageScrolled(currentPagerIndex, 0f)
                    }
                })
            }

            override fun removeOnPageChangeListener() {
                pagerGridLayoutManager.setPagerChangedListener(null)
            }

            override fun setCurrentItem(item: Int, smoothScroll: Boolean) {
                if (smoothScroll) {
                    pagerGridLayoutManager.smoothScrollToPagerIndex(item)
                } else {
                    pagerGridLayoutManager.scrollToPagerIndex(item)
                }

            }
        }

        binding.recyclerView.layoutManager = pagerGridLayoutManager

    }

    private fun loadFeedAd() {
        AdLoaders.startFeedAd(requireActivity(), binding.feedAdContainer)
    }

    override fun loadUrl(url: String, clearHistory: Boolean) {
        if (url.isBlank()) return
        if (!::webView.isInitialized) {
            webView = RocketWebView(requireContext(), browserViewModel.getWebConfig())
            webView.webViewCallback = this
            webView.browserDelegate = browserDelegate
            val layoutParams = CoordinatorLayout.LayoutParams(
                CoordinatorLayout.LayoutParams.MATCH_PARENT,
                CoordinatorLayout.LayoutParams.MATCH_PARENT
            )
            layoutParams.apply {
                behavior = ScrollingViewBehavior()
            }
            binding.coordinatorLayout.addView(webView, layoutParams)
        }
        mUrl = url

        _currentUrlFlow.tryEmit("复制当前网址" to url)

        binding.coordinatorLayout.visible()

        webView.clearHistory = clearHistory
        webView.loadUrl(url)
        binding.btnCollect.visibility = View.INVISIBLE

        _backStateFlow.tryEmit(binding.coordinatorLayout.isVisible)
        _forwardStateFlow.tryEmit(webView.canGoForward())
    }

    override fun onResume() {
        super.onResume()
        LOG.d(LOG_TAG, "BrowserFragment onResume")
    }

    override fun onPause() {
        super.onPause()
        LOG.d(LOG_TAG, "BrowserFragment onPause")
    }

    override fun onStart() {
        super.onStart()
        LOG.d(LOG_TAG, "BrowserFragment onStart")
        marqueeViewOnStart()
        val skinManager = QMUISkinManager.defaultInstance(requireContext())
        skinManager.addSkinChangeListener(onSkinChangeListener)
        onSkinChangeListener.onSkinChange(skinManager, -1, skinManager.currentSkin)

    }

    override fun onStop() {
        super.onStop()
        LOG.d(LOG_TAG, "BrowserFragment onStop")
        marqueeViewOnStop()
        QMUISkinManager.defaultInstance(requireContext())
            .removeSkinChangeListener(onSkinChangeListener)
    }

    override fun onDestroy() {
        if (::webView.isInitialized) {
            webView.browserDelegate = null
            webView.webViewCallback = null
            webView.destroy()
        }

        if (::shortCutEntryAdapter.isInitialized) {
            shortCutEntryAdapter.unregisterAdapterDataObserver(autoHeightObserver)
        }
        super.onDestroy()

    }

    override fun onProgressUpdate(progress: Int) {
        if (progress >= 100) {
            binding.progressBar.invisible()
            binding.progressBar.setProgress(0, false)
        } else {
            binding.progressBar.visible()
            binding.progressBar.setProgress(progress, true)
        }
    }

    override fun onTitleUpdate(title: String?) {
        LOG.d(LOG_TAG, "onTitleUpdate $title")
        this.title = title
        binding.textSearch.text = title
    }

    override fun onReceiveFavicon(url: String?, favicon: Bitmap) {
        LOG.d(LOG_TAG, "onReceiveFavicon")
        this.faviconBitmap = favicon
        url?.also {
            browserViewModel.updateFavicon(it, favicon)
        }

    }

    override fun onShowCustomView(view: View, callback: WebChromeClient.CustomViewCallback) {
        LOG.d(LOG_TAG, "onShowCustomView")
        fullScreenSupport.onShowCustomView(view, callback)
    }

    override fun onHideCustomView() {
        LOG.d(LOG_TAG, "onHideCustomView")
        fullScreenSupport.onHideCustomView()
    }

    override fun onPermissionRequest(request: PermissionRequest) {
        LOG.d(LOG_TAG, "onPermissionRequest")
    }

    override fun onShowFileChooser(
        chooseCallback: ValueCallback<Array<Uri>>, params: WebChromeClient.FileChooserParams
    ) {
        LOG.d(LOG_TAG, "onShowFileChooser")
    }

    override fun onAddBrowserHistory(title: String, url: String, favicon: Bitmap?) {
        LOG.d(LOG_TAG, "onAddBrowserHistory title $title , url $url")
        browserViewModel.addToHistory(title, url, favicon)
    }

    override fun onUrlChanged(
        title: String, newUrl: String, backForwardList: WebBackForwardList
    ) {
        if (!isAdded) return
        previewDirty = true
        adViewModel.increaseLoadCount() //每次添加历史记录，表示新的页面加载

        val newBackList = mutableListOf<BrowserTab.BackStackItem>(BrowserTab.BackStackItem.Home)
        for (i in 0 until backForwardList.size) {
            val item = backForwardList.getItemAtIndex(i)
            newBackList.add(BrowserTab.BackStackItem.Link(item.title, item.url))
        }

        _backStackFlow.tryEmit(newBackList)
        if (::webView.isInitialized) {
            _backStateFlow.tryEmit(binding.coordinatorLayout.isVisible) //只要WebView显示了，就可以返回到主页
            _forwardStateFlow.tryEmit(webView.canGoForward())
        }

        favoriteStateViewModel.updateCurrentUrl(newUrl)

        _currentUrlFlow.tryEmit(title to newUrl)
    }

    override fun updateSelectionRect(left: Float, top: Float, right: Float, bottom: Float) {
        LOG.d(LOG_TAG, "updateSelectionRect")
    }

    override fun onBlockIntent(chain: RocketWebViewClient.IntentBlockChain) {
        if (::blockIntentDialog.isInitialized && blockIntentDialog.isShowing) {
            return
        }

        blockIntentDialog = ConfirmWithCheckboxDialog(requireContext(), onSure = { checked ->
            if (checked) {
                chain.cancel()
            } else {
                chain.proceed()
            }
            browserViewModel.updateBlockIntent(checked)
        }, onDismiss = {
            chain.cancel()
        }).setTitle("提示").setContent("当前网页请求打开第三方APP，是否打开？")
            .setCheckText("禁止APP打开并不再询问")
        blockIntentDialog.show()
    }

    override fun getWebViewController(): WebViewController? {
        return if (::webView.isInitialized) webView else null
    }

    override fun getTitle(): String? {
        return title
    }

    override fun getFavicon(): Bitmap? {
        return faviconBitmap
    }

    override fun home() {
        title = "首页"
        faviconBitmap = null
        if (binding.coordinatorLayout.isGone()) return
        previewDirty = true
        binding.coordinatorLayout.gone()
        if (::webView.isInitialized) {
            webView.stopLoading()
        }
        _backStateFlow.tryEmit(false)
        _forwardStateFlow.tryEmit(::webView.isInitialized && webView.copyBackForwardList().size > 0)
    }

    override fun back() {
        if (::editSnackbar.isInitialized && editSnackbar.isShown) {
            shortCutEntryAdapter.updateEditMode(false)
            editSnackbar.dismiss()
        } else {
            if (::webView.isInitialized) {
                if (webView.canGoBack()) {
                    webView.goBack()
                    previewDirty = true
                } else if (binding.coordinatorLayout.isVisible) {
                    home()
                    previewDirty = true
                } else {
                    requireActivity().finish()
                }
            } else {
                requireActivity().finish()
            }
        }
    }

    override fun forward() {
        if (binding.coordinatorLayout.isGone()) {
            binding.coordinatorLayout.visible()
            _backStateFlow.tryEmit(true)
            _forwardStateFlow.tryEmit(webView.canGoForward())
            previewDirty = true
        } else {
            if (::webView.isInitialized) {
                if (webView.canGoForward()) {
                    webView.goForward()
                    _backStateFlow.tryEmit(true)
                    _forwardStateFlow.tryEmit(webView.canGoForward())
                    previewDirty = true
                }
            }
        }

    }

    override fun requestCapture(callback: (Bitmap?) -> Unit) {
        if (previewBitmap != null) {
            if (previewDirty) {
                previewBitmap?.recycle()
                previewBitmap = null

                BitmapUtils.captureView(requireActivity(), binding.root) {
                    previewBitmap = it
                    previewDirty = false
                    callback(it)
                }
            } else {
                callback(previewBitmap)
            }
        } else {
            BitmapUtils.captureView(requireActivity(), binding.root) {
                previewBitmap = it
                previewDirty = false
                callback(it)
            }
        }

    }

    override fun getPreview(): Bitmap? {
        return previewBitmap
    }

    override fun webViewVisible(): Boolean {
        return ::webView.isInitialized && binding.coordinatorLayout.isVisible
    }

    override fun toggleFavorite() {
        val selected = binding.btnCollect.isSelected
        if (selected) {
            favoriteStateViewModel.unFavorite()
            toast("取消收藏")
        } else {
            favoriteStateViewModel.favorite(title ?: "", faviconBitmap)
            toast("收藏成功")
        }
    }

    override fun reload() {
        if (::webView.isInitialized) {
            webView.reload()
        }
    }

    override fun getFragment(): Fragment {
        return this
    }

    override fun pause() {
        marqueeViewOnStop()
    }

    private fun marqueeViewOnStop() {
        if (!::binding.isInitialized) return
        binding.marqueeView1.stopFlipping()
        binding.marqueeView2.stopFlipping()
        binding.marqueeView3.stopFlipping()
    }

    private fun marqueeViewOnStart() {
        if (!::binding.isInitialized) return
        binding.marqueeView1.startFlipping()
        binding.marqueeView2.startFlipping()
        binding.marqueeView3.startFlipping()
    }

    override fun resume() {
        marqueeViewOnStart()
    }

    override fun destroy() {
        previewBitmap?.recycle()
        previewBitmap = null
    }

    override suspend fun getRawText(): String? {
        return if (::webView.isInitialized) {
            webView.getRawText()
        } else {
            null
        }
    }

    override fun enableReaderMode(enable: Boolean) {
        if (::webView.isInitialized) {
            webView.enableReaderMode(enable)
        }
    }

    override fun onHotSearchItemClick(item: HotSearchEntity, position: Int) {
        loadUrlOrSearch(item.url)
    }

    private fun loadUrlOrSearch(urlOrKeywords: String) {
        start<BrowserActivity> {
            action = BrowserActivity.InternalActionSearch
            putExtra(BrowserActivity.ExtraSearchKeyword, urlOrKeywords)
            putExtra(BrowserActivity.ExtraSearchOpenNewTab, false)
            putExtra(BrowserActivity.ExtraSearchClearHistory, true)
            putExtra(BrowserActivity.ExtraRequestLoadAd, true)
        }
    }

    override fun onEntryClicked(entry: ShortCutEntryEntity) {
        adViewModel.requestLoadAd()

        when (entry.type) {
            ShortCutEntryEntity.EntryTypeShortCut -> {
                entry.link?.also {
                    loadUrl(it, true)
                }
            }

            ShortCutEntryEntity.EntryTypeFavorites -> {
                if (entry.isFavoriteRoot()) {
                    FavoritesActivity.start(requireContext(), 0)
                } else {
                    entry.link?.also {
                        loadUrl(it, true)
                    }
                }
            }

            ShortCutEntryEntity.EntryTypeHistory -> {
                if (entry.isHistoryRoot()) {
                    FavoritesActivity.start(requireContext(), 1)
                } else {
                    entry.link?.also {
                        loadUrl(it, true)
                    }
                }
            }
        }

    }

    override fun onEntryAddClicked() {
        start<ShortCutActivity>()
    }

    override fun onEntryLongClicked(entry: ShortCutEntryEntity) {
        shortCutEntryAdapter.updateEditMode(true)
        editSnackbar = Snackbar.make(
            binding.recyclerView,
            "已进入编辑模式，可点击图标右上角的图标进行删除",
            Snackbar.LENGTH_INDEFINITE
        ).setAction("退出编辑") {
            shortCutEntryAdapter.updateEditMode(false)
        }.setTextColor(color(R.color.white)).setActionTextColor(color(R.color.transparentWhite60))

        editSnackbar.show()
    }

    override fun onEntryRemoveClicked(entry: ShortCutEntryEntity) {
        viewLifecycleOwner.lifecycleScope.launch {
            when (val result = shortCutEntryViewModel.removeShortCutEntry(entry)) {
                is Result.Error -> {
                    failToast(result.error.errorMessage)
                    LOG.d("error , ${result.error.errorMessage}")
                }

                else -> {

                }
            }

        }

    }

    class RecentlyBean(val names: ArrayList<String>)
}